package eu.urbain.gdocslauncher;

import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;

import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.drive.DriveScopes;

public class Common {

	private static String REDIRECT_URI = "http://localhost:5245";
	public static String CLIENT_ID = "836326172472-ios9hckkail92gp8ugcat2rp6e17rvso.apps.googleusercontent.com";
	public static String CLIENT_SECRET = "fYd3zWj6t3dPvG-t3eXLvXPE";

	public static void openWebpage(String urlString) {
		URL url;
		try {
			url = new URL(urlString);
			openWebpage(url);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}

	public static void openWebpage(URI uri) {
		Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
		if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
			try {
				desktop.browse(uri);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void openWebpage(URL url) {
		try {
			openWebpage(url.toURI());
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}

	public static GDocsLauncherConfig loadConfig() {

		try {
			// Open file to read from, named SavedObj.sav.
			FileInputStream saveFile = new FileInputStream("gDocsLauncher.conf");

			// Create an ObjectInputStream to get objects from save file.
			ObjectInputStream save = new ObjectInputStream(saveFile);

			// Now we do the restore.
			// readObject() returns a generic Object, we cast those back
			// into their original class type.
			// For primitive types, use the corresponding reference class.
			GDocsLauncherConfig gDocsLauncherConfig = (GDocsLauncherConfig) save.readObject();

			// Close the file.
			save.close();

			System.out.println("Config load successfully");

			return gDocsLauncherConfig;
			// This also closes saveFile.
		} catch (Exception exc) {

			System.out.println("Config load failed");
			// exc.printStackTrace();
			return null;
		}

	}

	public static GDocsLauncherConfig tryGetAuthorization() {

		GDocsLauncherConfig gDocsLauncherConfig;
		HttpTransport httpTransport = new NetHttpTransport();
		JsonFactory jsonFactory = new JacksonFactory();

		// launch listener to get the authorization code

		GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET,
				Arrays.asList(DriveScopes.DRIVE)).setAccessType("offline").setApprovalPrompt("force").build();

		String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
		// System.out.println("Please open the following URL in your browser then type the authorization code:");
		// System.out.println("  " + url);

		/*
		 * URL Sample https://accounts.google.com/o/oauth2/auth?
		 * access_type=online& approval_prompt=auto&
		 * client_id=836326172472-ios9hckkail92gp8ugcat2rp6e17rvso
		 * .apps.googleusercontent.com& redirect_uri=urn:ietf:wg:oauth:2.0:oob&
		 * response_type=code& scope=https://www.googleapis.com/auth/drive
		 */

		// Open browser to ask the authorization
		Common.openWebpage(url);

		String code = "";

		// launch http listener on port 8080 to get authorization code

		try {
			// Get the port to listen on
			int port = 5245;
			// Create a ServerSocket to listen on that port.
			ServerSocket ss = new ServerSocket(port);
			// Now enter an infinite loop, waiting for & handling connections.
			for (; code.equals("");) {
				// Wait for a client to connect. The method will block;
				// when it returns the socket will be connected to the client
				Socket client = ss.accept();

				// Get input and output streams to talk to the client
				BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
				PrintWriter out = new PrintWriter(client.getOutputStream());

				// Start sending our reply, using the HTTP 1.1 protocol
				out.print("HTTP/1.1 200 \r\n"); // Version & status code
				out.print("Content-Type: text/plain\r\n"); // The type of data
				out.print("Connection: close\r\n"); // Will close stream
				out.print("\r\n"); // End of headers

				// Now, read the HTTP request from the client, and send it
				// right back to the client as part of the body of our
				// response. The client doesn't disconnect, so we never get
				// an EOF. It does sends an empty line at the end of the
				// headers, though. So when we see the empty line, we stop
				// reading. This means we don't mirror the contents of POST
				// requests, for example. Note that the readLine() method
				// works with Unix, Windows, and Mac line terminators.
				String line;

				int lineNumber = 1;
				while ((line = in.readLine()) != null) {
					if (line.length() == 0)
						break;
					out.print(line + "   " + lineNumber + 5 + "\r\n");
					lineNumber++;

					if (line.contains("GET /?code=")) {
						code = line.substring(11, 74);

						out.print("code= " + code + "\r\n");
					}

				}

				// Close socket, breaking the connection to the client, and
				// closing the input and output streams
				out.close(); // Flush and close the output stream
				in.close(); // Close the input stream
				client.close(); // Close the socket itself

			}
			ss.close();

		}
		// If anything goes wrong, print an error message
		catch (Exception e) {
			System.err.println(e);
			System.err.println("Usage: java HttpMirror <port>");
		}

		// BufferedReader br = new BufferedReader(new
		// InputStreamReader(System.in));

		if (code.isEmpty()) {
			System.out.println("Can't get authorization code= " + code);
			System.exit(0);
		}

		try {
			// code = br.readLine();
			GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
			gDocsLauncherConfig = new GDocsLauncherConfig();
			gDocsLauncherConfig.setRefreshToken(response.getRefreshToken());
			gDocsLauncherConfig.setAccessToken(response.getAccessToken());
			System.out.println("refresh token : " + gDocsLauncherConfig.getRefreshToken());
			System.out.println("access token : " + gDocsLauncherConfig.getAccessToken());
			saveConfig(gDocsLauncherConfig);
			return gDocsLauncherConfig;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}

	}

	public static boolean saveConfig(GDocsLauncherConfig gDocsLauncherConfig) {

		try {
			// Catch errors in I/O if necessary.
			// Open a file to write to, named SavedObj.sav.
			FileOutputStream saveFile = new FileOutputStream("gDocsLauncher.conf");

			// Create an ObjectOutputStream to put objects into save file.
			ObjectOutputStream save = new ObjectOutputStream(saveFile);

			// Now we do the save.
			save.writeObject(gDocsLauncherConfig);

			// Close the file.
			save.close(); // This also closes saveFile.
			System.out.println("Config save successfully");
		} catch (Exception exc) {
			System.out.println("Config save failed");
			exc.printStackTrace();
			return false;
		}

		return true;

	}

	public static boolean isValidPathAndFile(List<String> allowedExtension, String path) {
		for (String extension : allowedExtension) {
			if (path.endsWith(extension)) {
				return true;
			}
		}
		return true;
	}

}
